using System.Collections.Generic;
using EternitySolver.Core;
using NUnit.Framework;

namespace EternitySolver.Tests
{
    [TestFixture]
    public class TileTests
    {
        [Test]
        public void VerifyTileIsCreatedCorrectly()
        {
            var tile = new Tile(1, 'a', 'b', 'c', 'd');
            Assert.AreEqual('a', tile.Top);
            Assert.AreEqual('b', tile.Right);
            Assert.AreEqual('c', tile.Bottom);
            Assert.AreEqual('d', tile.Left);
        }

        [Test]
        public void VerifyThatUnrotatedTileFitsSides()
        {
            var tile = new Tile(1, 'a', 'b', 'c', 'd');
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'b', 'c', 'd'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'b', null, 'd'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', null, null, 'd'))).Count);
        }

        [Test]
        public void VerifyThatUnrotatedTileDoesNotFitsSidesIfTileIsDifferent()
        {
            var tile = new Tile(1, 'd', 'd', 'd', 'd');
            Assert.AreEqual(0, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'b', 'c', 'd'))).Count);
            Assert.AreEqual(0, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'b', Tile.EDGE_TILE, 'd'))).Count);
            Assert.AreEqual(0, new List<TileOrientation>(tile.Fits(new TileSpecification('a', Tile.EDGE_TILE, Tile.EDGE_TILE, 'd'))).Count);
        }

        [Test]
        public void VerifyThatRotatedTileFitsSides()
        {
            var tile = new Tile(1, 'c', 'd', 'a', 'b');
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'b', 'c', 'd'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'b', null, 'd'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', null, null, 'd'))).Count);
        }

        [Test]
        public void VerifyThatUnrotatedTileFitsAllSidesIfAllSidesAreSame()
        {
            var tile = new Tile(1, 'a', 'a', 'a', 'a');
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, null, null, null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', null, null, null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, 'a', null, null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, null, 'a', null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, null, null, 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'a', null, null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', null, 'a', null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', null, null, 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, 'a', 'a', null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, 'a', null, 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, null, 'a', 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification(null, 'a', 'a', 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', null, 'a', 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'a', null, 'a'))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'a', 'a', null))).Count);
            Assert.AreEqual(1, new List<TileOrientation>(tile.Fits(new TileSpecification('a', 'a', 'a', 'a'))).Count);
        }

        [Test]
        public void VerifyCanCreate1x1Board()
        {
            var tiles = Board.Create(1,1,1).Tilebag.Ordered;
            Assert.AreEqual(1, tiles.Count);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Left);
        }

        [Test]
        public void VerifyCanCreate2x1Board()
        {
            var tiles = Board.Create(2,1,1).Tilebag.Ordered;
            Assert.AreEqual(2, tiles.Count);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Top);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[0].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Left);

            Assert.AreEqual(tiles[0].Right, tiles[1].Left);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Bottom);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[1].Left);
        }

        [Test]
        public void VerifyCanCreate1x2Board()
        {
            var tiles = Board.Create(1,2,1).Tilebag.Ordered;
            Assert.AreEqual(2, tiles.Count);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Right);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[0].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Left);

            Assert.AreEqual(tiles[0].Bottom, tiles[1].Top);

            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[1].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Left);
        }

        [Test]
        public void VerifyCanCreate2x2BoardWithOneColor()
        {
            var tiles = Board.Create(2,2,1).Tilebag.Ordered;
            Assert.AreEqual(4, tiles.Count);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Top);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[0].Right);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[0].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Left);

            Assert.AreEqual(tiles[0].Right, tiles[1].Left);
            Assert.AreEqual(tiles[0].Bottom, tiles[2].Top);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Right);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[1].Bottom);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[1].Left);

            Assert.AreEqual(tiles[1].Bottom, tiles[3].Top);
            Assert.AreEqual(tiles[2].Right, tiles[3].Left);

            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[2].Top);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[2].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[2].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[2].Left);

            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[3].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[3].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[3].Bottom);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[3].Left);
        }

        [Test]
        public void VerifyCanCreate2x2BoardWithMultipleColours()
        {
            var tiles = Board.Create(2,2,25).Tilebag.Ordered;

            Assert.AreEqual(4, tiles.Count);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Top);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[0].Right);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[0].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[0].Left);

            Assert.AreEqual(tiles[0].Right, tiles[1].Left);
            Assert.AreEqual(tiles[0].Bottom, tiles[2].Top);

            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[1].Right);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[1].Bottom);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[1].Left);

            Assert.AreEqual(tiles[1].Bottom, tiles[3].Top);
            Assert.AreEqual(tiles[2].Right, tiles[3].Left);

            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[2].Top);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[2].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[2].Bottom);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[2].Left);

            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[3].Top);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[3].Right);
            Assert.AreEqual(Tile.EDGE_TILE, tiles[3].Bottom);
            Assert.AreNotEqual(Tile.EDGE_TILE, tiles[3].Left);
        }
    }
}